﻿//
//                                                                                 (C) SocketCoder.Com 
// Note: This Project is just some simple samples, if you are looking for a production solution Visit 
// SocketCoder.Com to Buy The Full WCS Web Conferencing Solution Source Code. 
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Net.Sockets;
using VoiceEncoder;
using System.IO;
using System.Threading;
using NSpeex;

namespace SocketCoder_VoiceChat
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            FillData();
        }

       #region Global Declarations

        // Format
        int SamplesPerSecond; 
        int BitsPerSample;  
        int Channels;

        private CaptureSource _source = new CaptureSource();
        private MemoryAudioSink _sink;
        private bool _isRecording;
        private bool _isConnected = false;
        private delegate void mydelegate(byte[] buffer);
        private delegate void Streamdelegate(MemoryStream buffer);
        private delegate void ShowMessagedelegate(string MSG);
        private delegate void Enabledelegate(bool value);

        MediaElement mediaElement1 = new MediaElement();
        StreamingMediaSource WaveStream;
        MemoryStream ms = new MemoryStream();

        AudioFormat SelectedFormat;
        AudioCaptureDevice SelectedAudioDevice;
        ComboBox AvailableFormatsCombobox = new ComboBox();

        #endregion Global Declarations

       #region Encoding/Decoding Methods

        void FillData()
        {
            try
            {
                var audioFormats = (from format in _source.AudioCaptureDevice.SupportedFormats
                                    where format.WaveFormat == WaveFormatType.Pcm
                                    where format.BitsPerSample == 16
                                    where format.SamplesPerSecond >= 8000
                                    orderby format.BitsPerSample, format.SamplesPerSecond
                                    select format);

                foreach (AudioFormat format in audioFormats)
                {
                    FormatComboBox.Items.Add("Bits= " + format.BitsPerSample + " Samples= " + format.SamplesPerSecond + " Channels= " + format.Channels);
                    AvailableFormatsCombobox.Items.Add(format);
                }

                SelectedAudioDevice = CaptureDeviceConfiguration.GetDefaultAudioCaptureDevice();
                SelectedFormat = audioFormats.First();

                string SelectedFormatString = "Bits= " + SelectedFormat.BitsPerSample + " Samples= " + SelectedFormat.SamplesPerSecond + " Channels= " + SelectedFormat.Channels;
                FormatComboBox.SelectedValue = SelectedFormatString;

                MicrophonesInDevicesCombobox.Items.Add(SelectedAudioDevice.FriendlyName);
                MicrophonesInDevicesCombobox.SelectedValue = SelectedAudioDevice.FriendlyName;
                AvailableFormatsCombobox.SelectedItem = SelectedFormat;
            }
            catch
            {
                button1.IsEnabled = false;
                button2.IsEnabled = false;

                MicrophonesInDevicesCombobox.IsEnabled = false;
                FormatComboBox.IsEnabled = false;
                CodecComboBox.IsEnabled = false;

                MicrophonesInDevicesCombobox.Items.Add("No any avilable microphone!");
                MicrophonesInDevicesCombobox.SelectedValue = "No any avilable microphone!";

            }
        }

        void StartRecording()
        {
            try
            {
                BufferSizeLB.Content = 0;

                if (!_isRecording & _sink != null)
                {
                    _source.Start();
                    _isRecording = true;

                    button1.IsEnabled = false;
                    button2.IsEnabled = true;
                    MicrophonesInDevicesCombobox.IsEnabled = false;
                    CodecComboBox.IsEnabled = false;
                    VoiceQualitySlider.IsEnabled = true;

                }
                else if (!_isRecording & _sink==null)
                {
                    // Start First Time Only
                    if ((CaptureDeviceConfiguration.AllowedDeviceAccess | CaptureDeviceConfiguration.RequestDeviceAccess()) & (_source.State == CaptureState.Stopped))
                    {

                        _sink = new MemoryAudioSink();

                        _source.AudioCaptureDevice = SelectedAudioDevice;
                         _source.AudioCaptureDevice.DesiredFormat = SelectedFormat;
                         BitsPerSample = SelectedFormat.BitsPerSample;
                         SamplesPerSecond = SelectedFormat.SamplesPerSecond;
                         Channels = SelectedFormat.Channels;

                         string SelectedFormatString = "Bits= " + SelectedFormat.BitsPerSample + " Samples= " + SelectedFormat.SamplesPerSecond + " Channels= " + SelectedFormat.Channels;
                        FormatComboBox.SelectedValue = SelectedFormatString;
                        AvailableFormatsCombobox.SelectedIndex = FormatComboBox.SelectedIndex;

                        _sink.CaptureSource = _source;
                        
                        button1.IsEnabled = false;
                        button2.IsEnabled = true;
                        FormatComboBox.IsEnabled = false;
                        MicrophonesInDevicesCombobox.IsEnabled = false;
                        FormatComboBox.IsEnabled = false;
                        CodecComboBox.IsEnabled = false;
                        VoiceQualitySlider.IsEnabled = true;

                        _sink.OnBufferFulfill += new EventHandler(SendVoiceBuffer);

                        InitiatePlayback();

                        _source.Start();
                        _isRecording = true;

                    }

                }
            }
            catch (Exception ex)
            {
                ShowMessageBox("Your microphone may in use! or does not support it!" + ex.Message);
            }
        }

        void StopRecording()
        {
            if (_source != null & _sink!=null)
            {
                _source.Stop();
                _isRecording = false;
                button1.IsEnabled = true;
                button2.IsEnabled = false;
               

                MicrophonesInDevicesCombobox.IsEnabled = true;

                CodecComboBox.IsEnabled = true;

                BufferSizeLB.Content = 0;
            }
        }

        void SendVoiceBuffer(object VoiceBuffer, EventArgs e)
        {
            if (_isRecording)
            {
                byte[] Encodedbuffer = (byte[])VoiceBuffer;
                this.Dispatcher.BeginInvoke(new mydelegate(WriteBuffer), Encodedbuffer);
            }
        }

        void WriteBuffer(byte[] buffer)
        {
            BufferSizeLB.Content = buffer.Length;

            WaveStream.PutBufferToQueue(buffer);
        }

        void InitiatePlayback()
        {
            if (WaveStream == null & _sink != null)
            {
                WaveStream = new StreamingMediaSource(BitsPerSample, SamplesPerSecond, Channels);
                mediaElement1.Volume = 1.0;
                mediaElement1.SetSource(WaveStream);
                mediaElement1.AutoPlay = true;
            }
        }

        #endregion Encoding/Decoding Methods

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            StartRecording();
        }
        private void ShowMessageBox(string MSG)
        {
            MessageBox.Show(MSG);
        }
        private void ShowBufferSize(string Buffer_Size)
        {
            BufferSizeLB.Content = Buffer_Size;
        }
        private void EnableControl(bool value)
        {
            button1.IsEnabled = value;
            _isConnected = value;
        }

        private void button2_Click(object sender, RoutedEventArgs e)
        {
            StopRecording();
        }

        private void FormatComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (SelectedFormat != null)
            {
                AvailableFormatsCombobox.SelectedIndex = FormatComboBox.SelectedIndex;
                SelectedFormat = (AudioFormat) AvailableFormatsCombobox.SelectedItem;
            }
        }

        private void VoiceQualitySlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (_sink != null)
            {
             VoiceQLB.Content =  _sink.VoiceQuality = (int)VoiceQualitySlider.Value;
            }
        }

    }
}
